package main

import (
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"google.golang.org/protobuf/proto"

	pb "expeditionjourney/generated/proto"
)

var (
	config   = GetServerConfig()
	upgrader = websocket.Upgrader{
		ReadBufferSize:  config.ReadBufferSize,
		WriteBufferSize: config.WriteBufferSize,
		CheckOrigin: func(r *http.Request) bool {
			return true // 允许所有来源，实际生产环境中应该有更严格的检查
		},
	}
	clientsMutex sync.RWMutex
	clients      = make(map[*Client]bool)
)

// MessageHandler 定义一个消息处理器接口
type MessageHandler interface {
	HandleMessage(client *Client, req *pb.RequestMsg) (*pb.ResponseMsg, error)
}

// Client 表示一个WebSocket连接的客户端
type Client struct {
	conn           *websocket.Conn
	send           chan []byte
	id             string
	playerId       int32
	isLoggedIn     bool
	lastHeartbeat  time.Time
	sessionId      string
	handlers       map[int32]MessageHandler
	heartbeatTimer *time.Timer
}

// 创建一个新的客户端
func newClient(conn *websocket.Conn) *Client {
	client := &Client{
		conn:          conn,
		send:          make(chan []byte, 256),
		lastHeartbeat: time.Now(),
		handlers:      make(map[int32]MessageHandler),
	}

	// 注册各种消息处理器
	client.registerHandlers()

	return client
}

// 注册消息处理器
func (c *Client) registerHandlers() {
	// 注册心跳处理器
	c.handlers[ProtoCmds.CmdHeartbeatReq] = &HeartbeatHandler{}
	// 注册登录处理器
	c.handlers[ProtoCmds.CmdLoginReq] = &LoginHandler{}

	// 日志输出所有注册的处理器
	log.Printf("Registered handlers: HeartbeatHandler(%d), LoginHandler(%d)",
		ProtoCmds.CmdHeartbeatReq, ProtoCmds.CmdLoginReq)
}

// 读取客户端消息
func (c *Client) readPump() {
	defer func() {
		c.disconnect()
	}()

	// 设置最大消息大小，避免恶意大消息攻击
	c.conn.SetReadLimit(config.MaxMessageSize)

	// 设置读取超时
	c.conn.SetReadDeadline(time.Now().Add(config.ReadTimeout))
	c.conn.SetPongHandler(func(string) error {
		c.conn.SetReadDeadline(time.Now().Add(config.ReadTimeout))
		return nil
	})

	// 检查心跳超时
	c.heartbeatTimer = time.AfterFunc(config.HeartbeatTimeout, func() {
		log.Printf("Client %s heartbeat timeout", c.id)
		c.conn.Close()
	})

	for {
		_, message, err := c.conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				log.Printf("WebSocket read error: %v", err)
			}
			break
		}

		// 解析消息
		req := &pb.RequestMsg{}
		if err := proto.Unmarshal(message, req); err != nil {
			log.Printf("Failed to unmarshal message: %v", err)
			continue
		}

		// 根据消息类型分发处理
		handler, exists := c.handlers[req.Cmd]
		if !exists {
			log.Printf("No handler for command: %d", req.Cmd)
			c.sendErrorResponse(req.Cmd, req.Seq, pb.ErrorCode_ErrorProtocol)
			continue
		}

		// 处理消息
		resp, err := handler.HandleMessage(c, req)
		if err != nil {
			log.Printf("Error handling message: %v", err)
			c.sendErrorResponse(req.Cmd, req.Seq, pb.ErrorCode_ErrorSystemUnknown)
			continue
		}

		// 发送响应
		if resp != nil {
			respData, err := proto.Marshal(resp)
			if err != nil {
				log.Printf("Failed to marshal response: %v", err)
				continue
			}
			c.send <- respData
		}
	}
}

// 发送错误响应
func (c *Client) sendErrorResponse(cmd int32, seq int64, errorCode pb.ErrorCode) {
	resp := &pb.ResponseMsg{
		Cmd:       cmd,
		Seq:       seq,
		ErrorCode: errorCode,
	}

	respData, err := proto.Marshal(resp)
	if err != nil {
		log.Printf("Failed to marshal error response: %v", err)
		return
	}
	c.send <- respData
}

// 写入消息到客户端
func (c *Client) writePump() {
	ticker := time.NewTicker(config.PingInterval)
	defer func() {
		ticker.Stop()
		c.conn.Close()
	}()

	for {
		select {
		case message, ok := <-c.send:
			c.conn.SetWriteDeadline(time.Now().Add(config.WriteTimeout))
			if !ok {
				// 通道已关闭
				c.conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}

			w, err := c.conn.NextWriter(websocket.BinaryMessage)
			if err != nil {
				return
			}
			w.Write(message)

			// 一次性发送多个消息
			n := len(c.send)
			for i := 0; i < n; i++ {
				w.Write(<-c.send)
			}

			if err := w.Close(); err != nil {
				return
			}
		case <-ticker.C:
			c.conn.SetWriteDeadline(time.Now().Add(config.WriteTimeout))
			if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				return
			}
		}
	}
}

// 断开连接
func (c *Client) disconnect() {
	clientsMutex.Lock()
	delete(clients, c)
	clientsMutex.Unlock()

	if c.heartbeatTimer != nil {
		c.heartbeatTimer.Stop()
	}

	close(c.send)
	log.Printf("Client disconnected: %s", c.id)
}

// 处理WebSocket连接请求
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Error upgrading connection:", err)
		return
	}

	client := newClient(conn)

	// 生成唯一ID
	client.id = fmt.Sprintf("%p", conn)
	log.Printf("New client connected: %s", client.id)

	clientsMutex.Lock()
	clients[client] = true
	clientsMutex.Unlock()

	// 启动客户端的收发goroutine
	go client.writePump()
	go client.readPump()
}
